﻿using DapperBaseDal.Expressions;
using DapperExtensions;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace DapperBaseDal
{
    public interface IBaseRepository<T> where T : class
    {
        bool Buffered { get; set; }
        int? CommandTimeout { get; set; }
        IDbConnection Connection { get; }
        string ConnectionString { get; }
        DapperAsyncImplementor DapperImp { get; }
        DatabaseType DbType { get; }
        bool HasActiveTransaction { get; }
        IDbTransaction Transaction { get; }

        void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted);
        IDbConnection BuildConnection(string connectionString);
        DapperAsyncImplementor BuildDapperImplementor();
        void Close();
        void CloseConnection(bool disposed = true);
        void CloseTransaction(bool isRollback = true);
        void Commit();
        int Count(object predicate = null);
        int Count(Expression<Func<T, bool>> predicate);
        Task<int> CountAsync(object predicate = null);
        Task<int> CountAsync(Expression<Func<T, bool>> predicate);
        bool Delete(Expression<Func<T, bool>> predicate);
        bool Delete(object predicate);
        bool Delete(T entity);
        Task<bool> DeleteAsync(Expression<Func<T, bool>> predicate);
        Task<bool> DeleteAsync(object predicate);
        Task<bool> DeleteAsync(T entity);
        void Dispose();
        int Execute(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<int> ExecuteAsync(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        TAny ExecuteScalar<TAny>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<TAny> ExecuteScalarAsync<TAny>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        T Get(dynamic id);
        Task<T> GetAsync(dynamic id);
        T GetFirst(object predicate = null, object sort = null);
        T GetFirst(Expression<Func<T, bool>> predicate);
        T GetFirst(Expression<Func<T, bool>> predicate, IList<ISort> sort);
        T GetFirst(Expression<Func<T, bool>> predicate, object sort);
        T GetFirst(Expression<Func<T, bool>> predicate, SortDirection ascending, params Expression<Func<T, object>>[] sortingExpression);
        Task<T> GetFirstAsync(object predicate = null, object sort = null);
        Task<T> GetFirstAsync(Expression<Func<T, bool>> predicate);
        Task<T> GetFirstAsync(Expression<Func<T, bool>> predicate, IList<ISort> sort);
        Task<T> GetFirstAsync(Expression<Func<T, bool>> predicate, object sort);
        Task<T> GetFirstAsync(Expression<Func<T, bool>> predicate, SortDirection ascending, params Expression<Func<T, object>>[] sortingExpression);
        IEnumerable<T> GetList(object predicate = null, object sort = null);
        IEnumerable<T> GetList(Expression<Func<T, bool>> predicate, IList<ISort> sort = null);
        IEnumerable<T> GetList(Expression<Func<T, bool>> predicate, SortDirection ascending, params Expression<Func<T, object>>[] sortingExpression);
        IEnumerable<T> GetList(object predicate, IList<ISort> sort);
        Task<IEnumerable<T>> GetListAsync(object predicate = null, object sort = null);
        Task<IEnumerable<T>> GetListAsync(Expression<Func<T, bool>> predicate, IList<ISort> sort = null);
        Task<IEnumerable<T>> GetListAsync(Expression<Func<T, bool>> predicate, SortDirection ascending, params Expression<Func<T, object>>[] sortingExpression);
        Task<IEnumerable<T>> GetListAsync(object predicate, IList<ISort> sort);
        IEnumerable<T> GetPage(int pageIndex, int pageSize, out int totalCount, Expression<Func<T, bool>> predicate, IList<ISort> sort);
        IEnumerable<T> GetPage(int pageIndex, int pageSize, out int totalCount, Expression<Func<T, bool>> predicate, object sort);
        IEnumerable<T> GetPage(int pageIndex, int pageSize, out int totalCount, Expression<Func<T, bool>> predicate, SortDirection ascending, params Expression<Func<T, object>>[] sortingExpression);
        IEnumerable<T> GetPage(int pageIndex, int pageSize, out int totalCount, object predicate, IList<ISort> sort);
        IEnumerable<T> GetPage(int pageIndex, int pageSize, out int totalCount, object predicate, object sort);
        Task<Tuple<IEnumerable<T>, int>> GetPageAsync(int pageIndex, int pageSize, Expression<Func<T, bool>> predicate, IList<ISort> sort);
        Task<Tuple<IEnumerable<T>, int>> GetPageAsync(int pageIndex, int pageSize, Expression<Func<T, bool>> predicate, object sort);
        Task<Tuple<IEnumerable<T>, int>> GetPageAsync(int pageIndex, int pageSize, Expression<Func<T, bool>> predicate, SortDirection ascending, params Expression<Func<T, object>>[] sortingExpression);
        Task<Tuple<IEnumerable<T>, int>> GetPageAsync(int pageIndex, int pageSize, object predicate, IList<ISort> sort);
        Task<Tuple<IEnumerable<T>, int>> GetPageAsync(int pageIndex, int pageSize, object predicate, object sort);
        IEnumerable<T> GetSet(int firstResult, int maxResults, object predicate = null, object sort = null);
        IEnumerable<T> GetSet(int firstResult, int maxResults, Expression<Func<T, bool>> predicate, IList<ISort> sort);
        IEnumerable<T> GetSet(int firstResult, int maxResults, Expression<Func<T, bool>> predicate, object sort);
        IEnumerable<T> GetSet(int firstResult, int maxResults, Expression<Func<T, bool>> predicate, SortDirection ascending, params Expression<Func<T, object>>[] sortingExpression);
        IEnumerable<T> GetSet(int firstResult, int maxResults, object predicate, IList<ISort> sort);
        Task<IEnumerable<T>> GetSetAsync(int firstResult, int maxResults, object predicate = null, object sort = null);
        Task<IEnumerable<T>> GetSetAsync(int firstResult, int maxResults, Expression<Func<T, bool>> predicate, IList<ISort> sort);
        Task<IEnumerable<T>> GetSetAsync(int firstResult, int maxResults, Expression<Func<T, bool>> predicate, object sort);
        Task<IEnumerable<T>> GetSetAsync(int firstResult, int maxResults, Expression<Func<T, bool>> predicate, SortDirection ascending, params Expression<Func<T, object>>[] sortingExpression);
        Task<IEnumerable<T>> GetSetAsync(int firstResult, int maxResults, object predicate, IList<ISort> sort);
        void InitConnection(string connectionString);
        void Insert(IEnumerable<T> entities);
        dynamic Insert(T entity);
        Task InsertAsync(IEnumerable<T> entities);
        Task<dynamic> InsertAsync(T entity);
        void OpenConnection();
        IEnumerable<T> Query(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        IEnumerable<TAny> Query<TAny>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<IEnumerable<T>> QueryAsync(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<IEnumerable<TAny>> QueryAsync<TAny>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        DataSet QueryDataSet(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<DataSet> QueryDataSetAsync(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        T QueryFirst(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        TAny QueryFirst<TAny>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<T> QueryFirstAsync(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<TAny> QueryFirstAsync<TAny>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Tuple<IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>, IEnumerable<TFourth>, IEnumerable<TFifth>> QueryMultiple<TFirst, TSecond, TThird, TFourth, TFifth>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Tuple<IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>, IEnumerable<TFourth>> QueryMultiple<TFirst, TSecond, TThird, TFourth>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Tuple<IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>> QueryMultiple<TFirst, TSecond, TThird>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Tuple<IEnumerable<TFirst>, IEnumerable<TSecond>> QueryMultiple<TFirst, TSecond>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<Tuple<IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>, IEnumerable<TFourth>, IEnumerable<TFifth>>> QueryMultipleAsync<TFirst, TSecond, TThird, TFourth, TFifth>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<Tuple<IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>, IEnumerable<TFourth>>> QueryMultipleAsync<TFirst, TSecond, TThird, TFourth>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<Tuple<IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>>> QueryMultipleAsync<TFirst, TSecond, TThird>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        Task<Tuple<IEnumerable<TFirst>, IEnumerable<TSecond>>> QueryMultipleAsync<TFirst, TSecond>(string sql, object parameters = null, CommandType commandType = CommandType.Text);
        void Rollback();
        void RunInConnection(Action<IDbConnection> execSqlFunc);
        TAny RunInConnection<TAny>(Func<IDbConnection, TAny> execSqlFunc);
        Task RunInConnectionAsync(Func<IDbConnection, Task> execSqlFuncAsync);
        Task<TAny> RunInConnectionAsync<TAny>(Func<IDbConnection, Task<TAny>> execSqlFuncAsync);
        void RunInTransaction(Action<IDbTransaction> execTranFunc, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted);
        TAny RunInTransaction<TAny>(Func<IDbTransaction, TAny> execTranFunc, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted);
        bool Update(T entity, bool ignoreAllKeyProperties = false);
        Task<bool> UpdateAsync(T entity, bool ignoreAllKeyProperties = false);
        void UseConnection(IDbConnection connection);
        void UseTransaction(IDbTransaction dbTrans);
    }
}
